#region Using References

using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.IO;

#endregion

namespace Beaker.Services.FileSystem.Physical
{
	internal sealed class Folder
		: FolderBase
	{
		private readonly FolderBase _parent;
		private readonly DirectoryInfo _directoryInfo;

		internal Folder( FolderBase parent, DirectoryInfo directoryInfo )
			: base( parent )
		{
			Contract.Requires<ArgumentNullException>( parent != null );
			Contract.Requires<ArgumentNullException>( directoryInfo != null );

			_parent = parent;
			_directoryInfo = directoryInfo;
		}

		/// <summary>
		/// Gets the name of the entry
		/// </summary>
		public override string Name
		{
			get { return _directoryInfo.Name; }
		}

		/// <summary>
		/// Gets the file with the given name.
		/// </summary>
		/// <param name="fileName">The name of the file to get.</param>
		/// <returns>The file with the given name, or <c>null</c> when it could not be found.</returns>
		public override IFile GetFile( string fileName )
		{
			string rootPath = _directoryInfo.FullName;
			string filePath = Path.Combine( rootPath, fileName );

			if( !System.IO.File.Exists( filePath ) )
				return null;

			return 
				new File( this, new FileInfo( filePath ) )
					.WrapIfProvided();
		}

		/// <summary>
		/// Gets the folder with the given name.
		/// </summary>
		/// <param name="folderName">The name of the folder to get.</param>
		/// <returns>The folder with the given name, or <c>null</c> when it could not be found.</returns>
		public override IFolder GetFolder( string folderName )
		{
			string rootPath =  _directoryInfo.FullName;
			string folderPath = Path.Combine( rootPath, folderName );

			if( !Directory.Exists( folderPath ) )
				return null;

			var directoryInfo = new DirectoryInfo( folderPath );
			return new Folder( this, directoryInfo );
		}

		public override IEnumerable<IFileSystemEntry> GetEntries()
		{
			FileSystemInfo[] entries = _directoryInfo.GetFileSystemInfos( "*", SearchOption.TopDirectoryOnly );

			foreach( FileSystemInfo entry in entries )
			{
				var fileInfo = entry as FileInfo;
				if( fileInfo != null )
					yield return new File( this, fileInfo ).WrapIfProvided();
				if( entry is DirectoryInfo )
					yield return new Folder( this, (DirectoryInfo)entry );
			}
		}

		/// <summary>
		/// Gets the entry with the given name in this folder.
		/// </summary>
		/// <param name="entryName">Name of the entry to get.</param>
		/// <returns>The entry with the given name, or <c>null</c> when it could not be found.</returns>
		public override IFileSystemEntry GetEntry( string entryName )
		{
			string rootPath = _directoryInfo.FullName;
			string entryPath = Path.Combine( rootPath, entryName );

			if( Directory.Exists( entryPath ) )
			{
				var directoryInfo = new DirectoryInfo( entryPath );
				return new Folder( this, directoryInfo );
			}

			if( System.IO.File.Exists( entryPath ) )
			{
				var fileInfo = new FileInfo( entryPath );
				return new File( this, fileInfo ).WrapIfProvided();
			}

			return null;
		}
	}
}